package com.mldong.modules.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mldong.auth.ITokenStore;
import com.mldong.base.CommonPage;
import com.mldong.exception.ServiceException;
import com.mldong.holder.LoginUserHolder;
import com.mldong.modules.sys.dto.LoginParam;
import com.mldong.modules.sys.dto.UserPageParam;
import com.mldong.modules.sys.dto.UserParam;
import com.mldong.modules.sys.entity.User;
import com.mldong.modules.sys.enums.AuthErrEnum;
import com.mldong.modules.sys.enums.SysErrEnum;
import com.mldong.modules.sys.enums.UserAdminTypeEnum;
import com.mldong.modules.sys.mapper.MenuMapper;
import com.mldong.modules.sys.mapper.UserMapper;
import com.mldong.modules.sys.service.UserService;
import com.mldong.modules.sys.vo.LoginVO;
import com.mldong.modules.sys.vo.UserVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final ITokenStore tokenStore;
    private final MenuMapper menuMapper;
    @Value("${g.defaultPassword:123456}")
    private String defaultPassword;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(UserParam param) {
        param.setId(null);
        // 校验用户名唯一性
        checkUserName(param,false);
        // 校验手机号唯一性
        checkMobilePhone(param,false);
        // 密码加密处理
        String salt = RandomUtil.randomString(8);
        String enPassword = SecureUtil.md5(param.getPassword()+salt);
        // 部分字段由系统设置
        param.setAdminType(UserAdminTypeEnum.COMMON.getCode());
        User user = new User();
        BeanUtil.copyProperties(param, user);
        user.setPassword(enPassword);
        user.setSalt(salt);
        boolean success = super.save(user);
        // ServiceException.throwBiz(9999, "事务异常测试");
        return success;
    }

    @Override
    public boolean update(UserParam param) {
        // 校验用户名唯一性
        checkUserName(param,true);
        // 校验手机号唯一性
        checkMobilePhone(param,true);
        // 密码不允许更新
        param.setPassword(null);
        param.setSalt(null);
        // 不允许外部修改管理类型
        param.setAdminType(null);
        User user = new User();
        BeanUtil.copyProperties(param, user);
        return super.updateById(user);
    }

    @Override
    public CommonPage<UserVO> page(UserPageParam param) {
        IPage<UserVO> page = param.buildMpPage();
        QueryWrapper queryWrapper = param.buildQueryWrapper();
        if(ObjectUtil.isNotNull(param.getExcludeRoleId())) {
            String applySql = "t.id not in(select u3r.user_id from sys_user_role u3r where u3r.role_id={0})";
            queryWrapper.apply(applySql,param.getExcludeRoleId());
        }
        queryWrapper.eq("t.is_deleted",0);
        List<UserVO> list = baseMapper.selectCustom(page, queryWrapper);
        page.setRecords(list);
        return CommonPage.toPage(page);
    }

    @Override
    public UserVO findById(Long id) {
        return baseMapper.selectByIdCustom(id);
    }

    @Override
    public LoginVO login(LoginParam param) {
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(User::getUserName,param.getUserName());
        User user = baseMapper.selectOne(wrapper);
        if(user == null) {
            ServiceException.throwBiz(AuthErrEnum.USERNAME_OR_PASSWORD_ERR);
        }
        String enPassword = SecureUtil.md5(param.getPassword()+user.getSalt());
        if(!enPassword.equals(user.getPassword())) {
            ServiceException.throwBiz(AuthErrEnum.USERNAME_OR_PASSWORD_ERR);
        }
        LoginVO vo = new LoginVO();
        vo.setUserId(user.getId());
        vo.setUserName(user.getUserName());
        vo.setToken(StrUtil.uuid());
        vo.setAdminType(UserAdminTypeEnum.codeToEnum(user.getAdminType()));
        if(UserAdminTypeEnum.ADMIN.equals(vo.getAdminType())) {
            vo.setPerms(CollectionUtil.newArrayList(UserAdminTypeEnum.ADMIN.name().toLowerCase()));
        } else {
            vo.setPerms(menuMapper.selectMenuCodeByUserId(user.getId()));
        }
        // 分配权限
//        if(Integer.valueOf(1).equals(user.getUserType())) {
//            vo.setSuperAdmin(true);
//            vo.setPerms(new ArrayList<>());
//        } else if(Integer.valueOf(2).equals(user.getUserType())) {
//            vo.setSuperAdmin(false);
//            vo.setPerms(CollectionUtil.newArrayList("user:getById","role:page","role:getById"));
//        } else {
//            vo.setSuperAdmin(false);
//            vo.setPerms(new ArrayList<>());
//        }
        tokenStore.setToken(vo);
        return vo;
    }

    @Override
    public void logout(String token) {
        tokenStore.removeToken(token);
    }

    @Override
    public void updateAvatar(UserParam param) {
        User upUser = new User();
        upUser.setId(LoginUserHolder.getUserId());
        upUser.setAvatar(param.getAvatar());
        baseMapper.updateById(upUser);
    }

    @Override
    public void updateInfo(UserParam param) {
        User upUser = new User();
        param.setId(LoginUserHolder.getUserId());
        upUser.setId(LoginUserHolder.getUserId());
        upUser.setRealName(param.getRealName());
        upUser.setNickName(param.getNickName());
        upUser.setSex(param.getSex());
        upUser.setRemark(param.getRemark());
        upUser.setTel(param.getTel());
        if(StrUtil.isNotEmpty(param.getMobilePhone())) {
            checkMobilePhone(param, true);
            upUser.setMobilePhone(param.getMobilePhone());
        }
        baseMapper.updateById(upUser);
    }

    @Override
    public void resetPassword(List<Long> userIds) {
        // 超级管理员不允许被重置密码(adminType=1)
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.in(User::getId,userIds)
        .ne(User::getAdminType,UserAdminTypeEnum.ADMIN.getCode());
        List<User> userList = baseMapper.selectList(lambdaQueryWrapper);
        if(CollectionUtil.isEmpty(userList)) return;
        // 1. 获取默认密码
        // 2. 重新生成salt、password
        List<User> upUserList = userList.stream().map(item->{
            User user = new User();
            String salt = RandomUtil.randomString(8);
            String enPassword = SecureUtil.md5(defaultPassword+salt);
            user.setId(item.getId());
            user.setSalt(salt);
            user.setPassword(enPassword);
            return user;
        }).collect(Collectors.toList());
        // 3. 更新
        updateBatchById(upUserList);
    }

    /**
     * 校验用户名唯一性
     * @param param
     * @param isUpdate
     */
    private void checkUserName(UserParam param,boolean isUpdate) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(User::getUserName,param.getUserName());
        if(isUpdate) {
            // 更新时，需要排除当前id
            lambdaQueryWrapper.ne(User::getId,param.getId());
        }
        long count = baseMapper.selectCount(lambdaQueryWrapper);
        if(count>0) {
            // 抛出一个用户名已存在异常
            ServiceException.throwBiz(SysErrEnum.USER_NAME_EXISTS);
        }
    }
    /**
     * 校验手机号唯一性
     * @param param
     * @param isUpdate
     */
    private void checkMobilePhone(UserParam param,boolean isUpdate) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(User::getMobilePhone,param.getMobilePhone());
        if(isUpdate) {
            // 更新时，需要排除当前id
            lambdaQueryWrapper.ne(User::getId,param.getId());
        }
        long count = baseMapper.selectCount(lambdaQueryWrapper);
        if(count>0) {
            // 抛出一个手机号已存在异常
            ServiceException.throwBiz(SysErrEnum.MOBILE_PHONE_EXISTS);
        }
    }
}
